// Incremental Data Monitor
// Monitors changes in _DATA_POOL_ data and reports incremental differences
// Automatically clears baseline every 5 minutes for full data transmission

// Configuration
const BASELINE_RESET_INTERVAL = 1 * 60 * 1000; // 1 minute for testing (change back to 5 * 60 * 1000 for production)

// Minimal logging function for errors only
function errorLog(msg, data) {
    if (data === undefined) {
        node.error(`INCREMENTAL MONITOR - ${msg}`);
    } else {
        node.error(`INCREMENTAL MONITOR - ${msg}: ${JSON.stringify(data, null, 2)}`);
    }
}

// Check if baseline should be reset (every 5 minutes)
function shouldResetBaseline(baselineData) {
    if (!baselineData || !baselineData.timestamp) {
        return false; // No baseline exists
    }

    const now = new Date();
    const baselineTime = new Date(baselineData.timestamp);
    const timeDiff = now.getTime() - baselineTime.getTime();

    // Temporary debug info for testing
    node.warn(`BASELINE CHECK - Current: ${now.toISOString()}, Baseline: ${baselineData.timestamp}, Diff: ${Math.round(timeDiff / 1000)}s, Should Reset: ${timeDiff >= BASELINE_RESET_INTERVAL}`);

    return timeDiff >= BASELINE_RESET_INTERVAL;
}

try {
    // Get current data pool
    const currentDataPool = global.get('_DATA_POOL_');

    // Validate data pool structure
    if (!currentDataPool || !currentDataPool.props) {
        node.error("Invalid or empty data pool structure");
        return msg;
    }

    const currentData = currentDataPool.props;

    // Get baseline data
    let baselineData = global.get('_BASELINE_DATA_');
    const isFirstRun = !baselineData;

    // Check if baseline should be reset (every 5 minutes)
    const shouldReset = shouldResetBaseline(baselineData);
    if (shouldReset) {
        node.warn('BASELINE RESET - Clearing baseline for full transmission');
        global.set('_BASELINE_DATA_', null);
        baselineData = null;
    }

    // Need to establish baseline if first run OR after reset
    if (isFirstRun || shouldReset) {
        // Process and establish baseline data
        const processedBaseline = {};
        Object.keys(currentData).forEach(pointId => {
            const value = currentData[pointId];
            // Handle bits object structure
            let processedValue;
            if (typeof value === 'object' && value !== null && value.hasOwnProperty('orig')) {
                processedValue = value.orig;
            } else {
                processedValue = value;
            }
            // 跳过 null 值
            if (processedValue !== null) {
                processedBaseline[pointId] = processedValue;
            }
        });

        baselineData = {
            data: processedBaseline,
            timestamp: new Date().toISOString(),
            totalPoints: Object.keys(processedBaseline).length
        };

        global.set('_BASELINE_DATA_', baselineData);

        if (shouldReset) {
            // For baseline reset, send all current data as changes
            const allCurrentData = {};
            Object.keys(processedBaseline).forEach(pointId => {
                if (processedBaseline[pointId] !== null) {
                    allCurrentData[pointId] = processedBaseline[pointId];
                }
            });

            msg.payload = {
                type: 'baseline_reset',
                timestamp: baselineData.timestamp,
                totalPoints: baselineData.totalPoints,
                message: 'Baseline has been reset after 5-minute interval for full data transmission',
                isFullTransmission: true,
                summary: {
                    totalChanges: 0,
                    newPoints: Object.keys(allCurrentData).length,
                    removedPoints: 0,
                    totalCurrentPoints: Object.keys(allCurrentData).length,
                    totalPreviousPoints: 0
                },
                allChanges: allCurrentData
            };
        } else {
            // For first run, just establish baseline without sending data
            msg.payload = {
                type: 'baseline_established',
                timestamp: baselineData.timestamp,
                totalPoints: baselineData.totalPoints,
                message: 'Baseline data has been established for incremental monitoring',
                isFullTransmission: true
            };
        }

        return msg;
    }

    // Perform incremental comparison

    const baseline = baselineData.data;
    const differences = {};
    const newPoints = {};
    const removedPoints = {};

    // Compare current data with baseline
    Object.keys(currentData).forEach(pointId => {
        const currentValue = currentData[pointId];

        // Process current value
        let processedCurrentValue;
        if (typeof currentValue === 'object' && currentValue !== null && currentValue.hasOwnProperty('orig')) {
            processedCurrentValue = currentValue.orig;
        } else {
            processedCurrentValue = currentValue;
        }
        // 跳过 null 值
        if (processedCurrentValue === null) {
            return;
        }

        if (baseline.hasOwnProperty(pointId)) {
            // Check for value changes in existing points
            const baselineValue = baseline[pointId];
            if (processedCurrentValue !== baselineValue) {
                differences[pointId] = {
                    old: baselineValue,
                    new: processedCurrentValue,
                    change: processedCurrentValue - baselineValue
                };
            }
        } else {
            // New point detected
            newPoints[pointId] = processedCurrentValue;
        }
    });

    // Check for removed points
    Object.keys(baseline).forEach(pointId => {
        if (!currentData.hasOwnProperty(pointId)) {
            removedPoints[pointId] = baseline[pointId];
        }
    });

    const hasChanges = Object.keys(differences).length > 0 ||
        Object.keys(newPoints).length > 0 ||
        Object.keys(removedPoints).length > 0;

    if (hasChanges) {

        // Update baseline data
        const updatedBaseline = {};
        Object.keys(currentData).forEach(pointId => {
            const value = currentData[pointId];
            let processedValue;
            if (typeof value === 'object' && value !== null && value.hasOwnProperty('orig')) {
                processedValue = value.orig;
            } else {
                processedValue = value;
            }
            // 跳过 null 值
            if (processedValue !== null) {
                updatedBaseline[pointId] = processedValue;
            }
        });

        const newBaselineData = {
            data: updatedBaseline,
            timestamp: baselineData.timestamp, // 保持原始时间戳不变
            totalPoints: Object.keys(updatedBaseline).length,
            previousTimestamp: baselineData.timestamp
        };

        global.set('_BASELINE_DATA_', newBaselineData);

        // Combine all changes into a single object
        const allChanges = {};

        // Add modified points (with new values)
        Object.keys(differences).forEach(pointId => {
            if (differences[pointId].new !== null) {
                allChanges[pointId] = differences[pointId].new;
            }
        });

        // Add new points
        Object.keys(newPoints).forEach(pointId => {
            if (newPoints[pointId] !== null) {
                allChanges[pointId] = newPoints[pointId];
            }
        });

        // Return changes detected message with simplified format
        msg.payload = {
            type: 'changes_detected',
            timestamp: newBaselineData.timestamp,
            previousTimestamp: baselineData.timestamp,
            summary: {
                totalChanges: Object.keys(differences).length,
                newPoints: Object.keys(newPoints).length,
                removedPoints: Object.keys(removedPoints).length,
                totalCurrentPoints: Object.keys(currentData).length,
                totalPreviousPoints: Object.keys(baseline).length
            },
            allChanges: allChanges
        };

    } else {
        // Return no changes message
        msg.payload = {
            type: 'no_changes',
            timestamp: new Date().toISOString(),
            baselineTimestamp: baselineData.timestamp,
            totalPoints: Object.keys(currentData).length,
            message: 'No changes detected since last run'
        };
    }

} catch (error) {
    node.error("Error in incremental monitoring: " + error.message);
    errorLog('Error stack', error.stack);

    msg.payload = {
        type: 'error',
        timestamp: new Date().toISOString(),
        error: error.message
    };
}

return msg;